package com.rtsapp.server.logger.util;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 无锁的链表形式的队列
 *   * 队列长度无上限
 *   * 可多个生产者, 消费者
 *
 *   测试后: 性能和LinkedBlockingQueue差不太多, 如果性能和JDK差不多，那就没有多少必要使用啦
 */
public final class LockfreeLinkedQueue<T> {

    private final  AtomicReference< QueueNode<T> > head = new AtomicReference<>( null );
    private final AtomicReference< QueueNode<T> > tail = new AtomicReference<>( null );

    private final AtomicLong enqueueCnt = new AtomicLong( 0 );
    private final AtomicLong dequeueCnt = new AtomicLong( 0 );

    /**
     * 入队
     * @param data
     */
    public void enqueue( T data ){

        QueueNode<T> o = new QueueNode<T>();
        o.data = data;

        //如果是初始化状态
        if( tail.get() == null ){
            // 此处只尝试一次, 如果设置成功，退出，否则，继续下面的代码
            if( tail.compareAndSet( null, o ) ){
                return;
            }
        }


        QueueNode p;
        do {
            p = tail.get();
        } while ( !p.next.compareAndSet(null, o) );


        // 多个线程进入上面循环式时, 一次只有可能一个线程进入下列代码, 因此tail设置是安全的
        tail.set( o );

        //增加数量, 该值的设置可能有延后 ( 因为它和tail的原子行为被拆开 )
        enqueueCnt.incrementAndGet();
    }


    /**
     * 出队
     * @return
     */
    public  T dequeue( ){
        QueueNode<T> p ;
        do{
            p = head.get();
            if( p == null ){
                return null;
            }
        }while( head.compareAndSet( p , p.next.get() ) );

        return p.data;
    }

    /**
     * 入队的数量
     * @return
     */
    public long sizeEqueue(){
        return enqueueCnt.get();
    }

    /**
     * 队列目前的元素总个数
     * @return
     */
    public long size(){
        return enqueueCnt.get() - dequeueCnt.get();
    }


    private static class QueueNode<T>{
        T data;
        AtomicReference< QueueNode<T> > next = new AtomicReference<>( null );
    }


}
